package com.itcast.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itcast.dto.TechnicianQuery;
import com.itcast.entity.Technician;
import com.itcast.mapper.TechnicianMapper;
import com.itcast.service.TechnicianService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.UUID;

@Service
@Slf4j
public class TechnicianServiceImpl implements TechnicianService {

    @Value("${file.upload-dir}")
    private String uploadDir;

    @Autowired
    private TechnicianMapper technicianMapper;

    @PostConstruct
    public void initUploadDir() throws IOException {
        // 修复点：直接使用配置的路径，不再强制替换分隔符
        if (!uploadDir.endsWith("/")) {
            uploadDir += "/";  // 统一以 `/` 结尾（兼容Linux和Windows）
        }

        Path path = Paths.get(uploadDir).toAbsolutePath();
        if (!Files.exists(path)) {
            Files.createDirectories(path);
            log.info("上传目录创建成功: {}", path);
        }
        log.info("当前上传目录（绝对路径）: {}", path);
        log.info("目录权限 - 可读: {}, 可写: {}", Files.isReadable(path), Files.isWritable(path));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Technician saveTechnician(Technician technician, MultipartFile mainImg, MultipartFile listImg)
            throws IOException {
        try {
            // 1. 保存主图（添加详细日志）
            if (mainImg != null && !mainImg.isEmpty()) {
                log.info("开始保存主图，原始文件名: {}, 大小: {}字节",
                        mainImg.getOriginalFilename(), mainImg.getSize());
                String mainFilename = saveFile(mainImg);
                technician.setMainImg(mainFilename);
                log.info("主图保存完成，文件名: {}", mainFilename);
            }

            // 2. 保存列表图
            if (listImg != null && !listImg.isEmpty()) {
                log.info("开始保存列表图，原始文件名: {}, 大小: {}字节",
                        listImg.getOriginalFilename(), listImg.getSize());
                String listFilename = saveFile(listImg);
                technician.setListImg(listFilename);
                log.info("列表图保存完成，文件名: {}", listFilename);
            }

            // 3. 保存到数据库
            technicianMapper.insert(technician);
            return technician;
        } catch (IOException e) {
            log.error("文件保存失败，已触发事务回滚", e);
            throw e;
        }
    }

    /**
     * 保存文件到服务器并返回文件名（安全增强版）
     */
    private String saveFile(MultipartFile file) throws IOException {
        // 1. 基础校验
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("上传文件不能为空");
        }

        // 2. 生成文件名
        String originalFilename = file.getOriginalFilename();
        String extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        String filename = UUID.randomUUID() + extension;
        log.debug("生成文件名: {}", filename);

        // 3. 构建目标路径
        Path uploadPath = Paths.get(uploadDir).toAbsolutePath().normalize();
        Path destPath = uploadPath.resolve(filename).normalize();

        // 4. 安全校验
        if (!destPath.startsWith(uploadPath)) {
            throw new IOException("非法文件路径: " + destPath);
        }

        // 5. 保存文件（NIO方式，更可靠）
        try (InputStream inputStream = file.getInputStream()) {
            Files.copy(inputStream, destPath, StandardCopyOption.REPLACE_EXISTING);
            log.info("文件保存成功，路径: {}，大小: {}字节",
                    destPath, Files.size(destPath));
        }

        return filename;
    }

    @Override
    public PageInfo<Technician> getTechniciansByPage(TechnicianQuery query, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<Technician> technicians = technicianMapper.selectByPage(query);
        return new PageInfo<>(technicians);
    }

    @Override
    public Technician selectById(int id) {
        return technicianMapper.selectById(id);
    }
}